package com.leyou.order.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.leyou.client.item.ItemClient;
import com.leyou.client.seckill.SeckillClient;
import com.leyou.client.user.UserClient;
import com.leyou.common.auth.pojo.UserHolder;
import com.leyou.common.auth.pojo.UserInfo;
import com.leyou.common.constants.LyConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.pojo.Sku;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.MyOrder;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.dto.OrderVO;
import com.leyou.order.dto.SeckillOrderDTO;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.SeckillMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderDetail;
import com.leyou.order.pojo.OrderLogistics;
import com.leyou.order.pojo.OrderStatusEnum;
import com.leyou.order.utils.PayHelper;
import com.leyou.seckill.pojo.Seckill;
import com.leyou.user.pojo.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单业务
 */
@Service
@Transactional
@Slf4j
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayHelper payHelper;
    @Autowired
    private SeckillClient seckillClient;
    @Autowired
    private SeckillMapper seckillMapper;


    @GlobalTransactional
    public Long buildOrder(OrderDTO orderDTO) {
        //获取当前登录有用户信息
        UserInfo user = UserHolder.getUser();

        //1.保存订单信息
        Order order = new Order();
        //1.1 订单号
        order.setOrderId(idWorker.nextId());
        
        //1.2 总金额
        //1）获取所有商品参数
        // List<CartDTO> 格式： [ {"100":20,"200":15....}  ]
        List<CartDTO> carts = orderDTO.getCarts();

        //2）把List<CartDTO>转换为Map结构：   {"100":20,"200":15....}
        //Collectors.toMap():
         //  参数一： key的映射。 收集的Map集合的key元素来源于carts集合中元素（CartDTO）的哪个字段
         //  参数二： value的映射。 收集的Map集合的value元素来源于carts集合中元素（CartDTO）的哪个字段
        Map<Long,Integer> cartMap = carts.stream().collect(Collectors.toMap( CartDTO::getSkuId , CartDTO::getNum ));

        //3）获取skuId集合
        List<Long> skuIdList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());

        //4）根据skuId集合查询Sku对象集合
        List<Sku> skuList = itemClient.findSkusByIds(skuIdList);

        //5）计算商品总价
        Long totalFee = skuList.stream().mapToLong(sku -> sku.getPrice()*cartMap.get(sku.getId())).sum();

        order.setTotalFee(totalFee);

        //1.3 实付金额
        order.setActualFee(1L);
        //1.4 优惠活动ID
        order.setPromotionIds("1");
        //1.5 支付类型
        order.setPaymentType(orderDTO.getPaymentType());
        //1.6 邮费
        order.setPostFee(0L);
        //1.7 用户ID
        order.setUserId(user.getId());
        //1.8 发票类型
        order.setInvoiceType(0);
        //1.9 订单来源
        order.setSourceType(2);
        //1.10 订单状态
        order.setStatus(OrderStatusEnum.INIT.value());

        orderMapper.insert(order);

        //2.保存订单详情信息
        //1）遍历所有Sku对象
        skuList.forEach(sku -> {
            OrderDetail orderDetail = new OrderDetail();
            //2.1 详情ID
            orderDetail.setId(idWorker.nextId());
            //2.2 订单号
            orderDetail.setOrderId(order.getOrderId());
            //2.3 商品id
            orderDetail.setSkuId(sku.getId());
            //2.4 商品数量
            orderDetail.setNum(cartMap.get(sku.getId()));
            //2.5 标题
            orderDetail.setTitle(sku.getTitle());
            //2.6 特有参数
            orderDetail.setOwnSpec(sku.getOwnSpec());
            //2.7 价格
            orderDetail.setPrice(sku.getPrice());
            //2.8 图片
            orderDetail.setImage(sku.getImages());

            orderDetailMapper.insert(orderDetail);
        });

        //3.保存订单物流信息
        AddressDTO addressDTO = userClient.findAddressById(user.getId(), orderDTO.getAddressId());

        //3.1 把收货人信息拷贝到OrderLogistics对象中
        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO,OrderLogistics.class);
        //3.2 订单号
        orderLogistics.setOrderId(order.getOrderId());
        //3.3 物流单号
        orderLogistics.setLogisticsNumber("2232323");
        //3.4 物流公司
        orderLogistics.setLogisticsCompany("菜鸟物流");

        orderLogisticsMapper.insert(orderLogistics);

        //4.扣减购买商品的库存量
        itemClient.minusStock(cartMap);

        //模拟异常
        //int i = 10/0;


        return order.getOrderId();
    }

    public OrderVO findOrderById(Long id) {
        //1.查询订单表数据
        Order order = orderMapper.selectById(id);

        //2.把Order拷贝到OrderVo
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);

        //2.查询订单详情
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(id);
        QueryWrapper<OrderDetail> orderDetailQueryWrapper = Wrappers.query(orderDetail);
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(orderDetailQueryWrapper);
        orderVO.setDetailList(orderDetails);

        //3.查询订单物流
        OrderLogistics orderLogistics = orderLogisticsMapper.selectById(id);
        orderVO.setLogistics(orderLogistics);

        return orderVO;
    }

    public String getPayUrl(Long id) {
        String payKey = LyConstants.PAY_URL_PRE+id;

        //1.从redis取出支付链接
        String payUrl = redisTemplate.opsForValue().get(payKey);

        //2.判断redis是否存在该订单的支付链接
        if(payUrl!=null){
            //4.如果存在支付链接，则直接取出返回即可
            return payUrl;
        }

        //根据订单ID查询订单
        Order order = orderMapper.selectById(id);

        //3.如果不存在支付链接，则微信下单API获取支付链接
        payUrl = payHelper.getPayUrl(id,order.getActualFee());

        //4. 把支付链接存入redis，设置有效期为3小时
        redisTemplate.opsForValue().set(payKey,payUrl,3, TimeUnit.HOURS);

        //5.返回生成的支付链接
        return payUrl;
    }

    public void wxNotify(Map<String, String> paramsMap) {
        //1.获取订单号和支付金额
        Long orderId =  Long.valueOf(paramsMap.get("out_trade_no"));
        Long totalFee = Long.valueOf(paramsMap.get("total_fee"));

        //2.根据订单号查询订单
        Order order = orderMapper.selectById(orderId);

        //3.判断订单是否存在，如果不存在，抛出异常
        if(order==null){
            log.error("【支付回调】订单不存在！");
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        //4.判断支付金额是否一致
        if(order.getActualFee()!=totalFee){
            log.error("【支付回调】支付金额不一致！");
            throw new LyException(ExceptionEnum.PAY_FEE_NOT_ERROR);
        }

        //5.判断订单状态如果已经支付过了，无需支付了
        if(order.getStatus()!=1){
            log.error("【支付回调】订单已经支付，无需重复支付！");
            throw new LyException(ExceptionEnum.ORDER_HAS_PAY_ERROR);
        }

        //6.更新订单状态以及支付时间
        try {
            order.setStatus(2);
            order.setPayTime(new Date());
            orderMapper.updateById(order);

            log.info("【支付回调】订单状态更新成功");


        } catch (Exception e) {
            e.printStackTrace();
            log.error("【支付回调】订单状态更新失败");
        }


    }

    public Integer checkState(Long id) {
        Order order = orderMapper.selectById(id);
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }


    @GlobalTransactional
    public void buildSeckillOrder(Map<String, String> seckillMap) {

        Long seckillOrderId = Long.valueOf(seckillMap.get("seckillOrderId"));
        //1.保存订单信息
        Order order = new Order();
        //1.1 订单号
        order.setOrderId(seckillOrderId);

        String seckillOrderDTOJson = seckillMap.get("seckillOrderDTO");

        SeckillOrderDTO seckillOrderDTO = JsonUtils.toBean(seckillOrderDTOJson,SeckillOrderDTO.class);
        UserInfo userInfo = JsonUtils.toBean(seckillMap.get("userInfo"),UserInfo.class) ;

        Seckill seckill = new Seckill();
        seckill.setId(seckillOrderDTO.getId());
        QueryWrapper<Seckill> query = Wrappers.query(seckill);
        seckill = seckillMapper.selectOne(query);

        //5）计算商品总价
        Long totalFee = seckill.getPrice() * seckillOrderDTO.getNum();

        order.setTotalFee(totalFee);

        //1.3 实付金额
        order.setActualFee(1L);
        //1.4 优惠活动ID
        order.setPromotionIds("1");
        //1.5 支付类型
        order.setPaymentType(seckillOrderDTO.getPaymentType());
        //1.6 邮费
        order.setPostFee(0L);
        //1.7 用户ID
        order.setUserId(userInfo.getId());
        //1.8 发票类型
        order.setInvoiceType(0);
        //1.9 订单来源
        order.setSourceType(2);
        //1.10 订单状态
        order.setStatus(OrderStatusEnum.INIT.value());
        orderMapper.insert(order);

        //2.保存订单详情信息
        OrderDetail orderDetail = new OrderDetail();
        //2.1 详情ID
        orderDetail.setId(idWorker.nextId());
        //2.2 订单号
        orderDetail.setOrderId(order.getOrderId());
        //2.3 商品id
        orderDetail.setSkuId(seckill.getId());
        //2.4 商品数量
        orderDetail.setNum(seckillOrderDTO.getNum());
        //2.5 标题
        orderDetail.setTitle(seckill.getTitle());
        //2.6 特有参数
        orderDetail.setOwnSpec(seckill.getOwnSpec());
        //2.7 价格
        orderDetail.setPrice(seckill.getPrice());
        //2.8 图片
        orderDetail.setImage(seckill.getImages());

        orderDetailMapper.insert(orderDetail);


        //3.保存订单物流信息
        AddressDTO addressDTO = userClient.findAddressById(userInfo.getId(), seckillOrderDTO.getAddressId());

        //3.1 把收货人信息拷贝到OrderLogistics对象中
        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        //3.2 订单号
        //3.2 订单号
        orderLogistics.setOrderId(order.getOrderId());
        //3.3 物流单号
        orderLogistics.setLogisticsNumber("2232323");
        //3.4 物流公司
        orderLogistics.setLogisticsCompany("菜鸟物流");

        orderLogisticsMapper.insert(orderLogistics);

        seckill.setStock(seckill.getStock()-seckillOrderDTO.getNum());

        seckillMapper.updateById(seckill);
    }




    /**
     * 查询我的订单内容
     * @param status
     * @param page
     * @param rows
     * @return
     */
    public PageResult<List<MyOrder>> findOrderPage(Integer status, Integer page, Integer rows) {
        //封装分页参数
        IPage <Order> iPage =new Page(page,rows);
        //获取用户id
        UserInfo user = UserHolder.getUser();
/*        //查出用户的所有订单
         Order userOrder = new Order();
          userOrder.setUserId(userInfo.getId());*/

        //定义一个查询条件
        QueryWrapper <Order> queryWrapper = Wrappers.query();

        if(status==null){
            //状态码为空
            queryWrapper.eq("user_id",user.getId());
        }else {
            //状态码不为空
            queryWrapper.eq("status",status).eq("user_id",user.getId());
        }

        iPage = orderMapper.selectPage(iPage, queryWrapper);
        //把ipage里面的order的id中获取orderVo信息
        List <Order> orders = iPage.getRecords();
        //定义一个orderVO集合用于接收数据
        List<MyOrder> myOrderList =new ArrayList <>();
        //遍历所有所有oders获取orderVO
        orders.forEach(order -> {
            // OrderVO orderVO = this.findOrderById(order.getOrderId());
            MyOrder myOrder = BeanHelper.copyProperties(order, MyOrder.class);
            OrderDetail orderDetail1 = new OrderDetail();
            orderDetail1.setOrderId(order.getOrderId());
            QueryWrapper <OrderDetail> wrapper = Wrappers.query(orderDetail1);
            List <OrderDetail> orderDetail = orderDetailMapper.selectList(wrapper);
            myOrder.setOrderId(order.getOrderId().toString());
            myOrder.setDetailList(orderDetail);
            myOrderList.add(myOrder);
        });

        //3.4 封装PageResult对象
        PageResult<List<MyOrder>> pageResult = new PageResult(iPage.getTotal(),iPage.getPages(),myOrderList);


        return pageResult;
    }
}
